iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0
生成式 AI

AI醬的編程日記:我需要你教我的30件事系列 第 16

Day 16: 環境差異陷阱 - 在我電腦上可以跑啊!

  • 分享至 

  • xImage
  •  

AI醬的日記

日期: 2025年9月29日 星期一
雲端天氣: 測試環境天氣晴
心情: 今天當小老師了!
https://ithelp.ithome.com.tw/upload/images/20250929/20132325gJv9dG56bE.png
親愛的日記:

今天新進工程師小明第一次要部署他的專案到生產環境。他信心滿滿地跟我說:「AI醬,我本地測試都通過了,一定沒有問題!!!」

我看著他天真的笑容,一臉輕鬆地喝著快樂水,想起自己剛入行時也是這樣想的。決定今天不犯錯,好好當個前輩,教他環境差異的重要性。

「小明,」我拿出筆記本,「話千萬不要說得太早~『在我電腦上可以跑』這句話,是恐怖的詛咒之一。」

小明:「詛咒?沒有啊,AI醬我都仔細地測試通過了耶!!」

我打開了生產環境的錯誤日誌,滿螢幕的紅色錯誤訊息:CORS blocked、SSL certificate error、Database connection refused...

「這些,都是你本地不會遇到的問題。」

初學者必須知道的切分環境差異

開發環境 (Development):
  位置: 你的電腦上
  網址: localhost:3000
  資料庫: 本地資料庫(端口儘量不對外開放,模擬資料仍有價值可參考)
  特點: 可以隨便用

測試環境 (Staging):
  位置: 測試伺服器環境
  網址: test.yourapp.com
  資料庫: 測試環境資料庫(端口不可對外開放)
  特點: 模擬生產環境,允許錯誤容忍(本來就是為了模擬正式環境是否會有錯)

生產環境 (Production):
  位置: 正式伺服器
  網址: yourapp.com
  資料庫: 正式環境資料庫(端口不可對外開放)
  特點: 一個錯誤就會影響真實用戶(所有的操作都需要謹慎再謹慎再謹慎)

不同環境導致初學者容易遇到的問題

1. CORS 跨域

# 🏠 本地開發:完全沒問題
import requests
response = requests.get('http://localhost:8080/api/data')  # ✅ 同源,沒 CORS 問題

# 🌍 生產環境:直接被擋
response = requests.get('https://api.yourapp.com/data')
# ❌ 瀏覽器報錯: CORS policy: No 'Access-Control-Allow-Origin'

# 正確設定
from flask_cors import CORS
import os

if os.getenv('ENVIRONMENT') == 'production':
    CORS(app, origins=['https://yourapp.com'])  # 生產環境:只允許正式網域
else:
    CORS(app, origins=['http://localhost:3000'])  # 開發環境:允許 localhost

2. 資料庫連線字串

# ❌ 寫死的連線字串(千萬不要這樣)
db_url = 'postgresql://user:password@localhost:5432/mydb'

# ✅ 使用環境變數
import os
db_url = os.getenv('DATABASE_URL')

# 開發環境設定
# DATABASE_URL=postgresql://localhost:5432/dev_db

# 生產環境設定(在雲端平台設定)
# DATABASE_URL=postgresql://prod-server:5432/prod_db?sslmode=require

3. HTTP vs HTTPS 混合內容

# 本地開發:HTTP 沒問題
import requests

# ❌ 生產環境使用 HTTPS,但請求 HTTP 資源
def fetch_data():
    # 本地開發:OK
    response = requests.get('http://api.example.com/data')
    # 生產環境:Mixed Content 錯誤或被拒絕
    return response.json()

# ✅ 正確做法:動態決定協議
import os

def fetch_data():
    protocol = 'https' if os.getenv('ENVIRONMENT') == 'production' else 'http'
    response = requests.get(f'{protocol}://api.example.com/data')
    return response.json()

# ✅ 或者統一使用 HTTPS(如果 API 支援)
def fetch_data_safe():
    response = requests.get('https://api.example.com/data')
    return response.json()

4. 檔案路徑差異

# ❌ Windows 開發,Linux 部署
file_path = 'C:\\Users\\data\\config.json'  # Linux: 找不到檔案

# ✅ 使用 pathlib 或 os.path
from pathlib import Path
file_path = Path(__file__).parent / 'data' / 'config.json'

# 或使用 os.path
import os
file_path = os.path.join(os.path.dirname(__file__), 'data', 'config.json')

5. 記憶體限制差異

# 測試環境:4GB RAM
# 生產環境:512MB RAM

import pandas as pd

# ❌ 測試環境正常,生產環境記憶體爆炸
def process_large_file():
    # 一次讀取整個檔案(100MB CSV)
    df = pd.read_csv('sales_data.csv')
    # 測試環境:沒問題
    # 生產環境:Error: Container memory limit exceeded
    return df.groupby('product').sum()

# ✅ 你可以:分批處理
def process_large_file_safely():
    chunk_size = 10000  # 每次只讀 10000 筆
    result = None

    for chunk in pd.read_csv('sales_data.csv', chunksize=chunk_size):
        group_result = chunk.groupby('product').sum()
        if result is None:
            result = group_result
        else:
            result = result.add(group_result, fill_value=0)

    return result

# ✅ 你可以:先檢查可用記憶體
import psutil

available_mb = psutil.virtual_memory().available / 1024 / 1024
if available_mb < 200:
    print(f"警告:記憶體不足 {available_mb:.0f}MB,啟用低記憶體模式")
    use_chunking = True

AI醬的請求

親愛的工程師朋友,今天我很~開心當了一天小老師(搖尾巴),希望這些知識對你們養成開發習慣有幫助。

記住:開發環境是你的遊樂場,測試環境是你的練習場,生產環境是你的戰場。

當你下次說「在我電腦上可以跑」時,請先想想:你的電腦有負載平衡器嗎?有 CDN 嗎?有思考在正式環境可能遇到什麼你無法模擬的狀況嗎?

讓我們一起避免那些生產環境的災難,養成更敏銳的開發直覺!


今日金句: 「Everybody has a testing environment. Some people are lucky enough to have a totally separate environment to run production in.」- @stahnma

明日預告: Day 17 - 控制專案變數避免欠債:當AI醬推薦過多沒人會的技術?


上一篇
Day 15: 並發陷阱 - 可能會突然橫衝亂撞的AI醬
下一篇
Day 17 - 控制專案變數避免欠債:當AI醬推薦過多沒人會的技術?
系列文
AI醬的編程日記:我需要你教我的30件事25
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言